package com.meilai.project.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.extension.toolkit.SqlHelper;
import com.meilai.project.dto.workflow.*;
import com.meilai.project.entity.personnel.org.Department;
import com.meilai.project.entity.system.User;
import com.meilai.project.entity.workflow.*;
import com.meilai.project.exception.CommonException;
import com.meilai.project.service.personnel.org.DepartmentService;
import com.meilai.project.service.system.MessageCenterService;
import com.meilai.project.service.system.UserService;
import com.meilai.project.service.workflow.*;
import io.swagger.annotations.ApiModelProperty;
import lombok.extern.log4j.Log4j2;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ReflectionUtils;

import javax.annotation.PostConstruct;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.io.Serializable;
import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @author 张驰
 * @date 2020/5/27
 */

@Component
@Log4j2
@SuppressWarnings("unchecked")
public class WorkFlowUtil<T extends FlowBusinessDataSuperEntity,M extends BaseMapper<T>> {
    private final static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Autowired
    private UserService userService;
    @Autowired
    private DepartmentService departmentService;
    @Autowired
    private WFDataService wfDataService;
    @Autowired
    private WFCheckService wfCheckService;
    @Autowired
    private WorkFlowDefaultService workFlowDefaultService;
    @Autowired
    private WFDataProcessingService wfDataProcessingService;
    @Autowired
    private WFDataFinishedService wfDataFinishedService;
    @Autowired
    private WFDataDeleteService wfDataDeleteService;
    @Autowired
    private VWFDataProcessingService vwfDataProcessingService;
    @Autowired
    private WFDataProcessingLogService wfDataProcessingLogService;
    @Autowired
    private WFDataBackService wfDataBackService;
    @Autowired
    private WFDataDraftService wfDataDraftService;
    @Autowired
    private WFCurCheckerService wfCurCheckerService;
    @Autowired
    private MessageCenterService messageCenterService;

    public static WorkFlowUtil workFlowUtil;

    @PostConstruct
    public void init() {
        workFlowUtil = this;
        workFlowUtil.userService = this.userService;
        workFlowUtil.departmentService = this.departmentService;
        workFlowUtil.wfDataService = this.wfDataService;
        workFlowUtil.wfCheckService = this.wfCheckService;
        workFlowUtil.workFlowDefaultService = this.workFlowDefaultService;
        workFlowUtil.wfDataProcessingService = this.wfDataProcessingService;
        workFlowUtil.wfDataFinishedService = this.wfDataFinishedService;
        workFlowUtil.wfDataDeleteService = this.wfDataDeleteService;
        workFlowUtil.vwfDataProcessingService = this.vwfDataProcessingService;
        workFlowUtil.wfDataBackService = this.wfDataBackService;
        workFlowUtil.wfDataDraftService = this.wfDataDraftService;
        workFlowUtil.wfCurCheckerService = this.wfCurCheckerService;
        workFlowUtil.wfDataProcessingLogService = this.wfDataProcessingLogService;
        workFlowUtil.messageCenterService = this.messageCenterService;
    }

    @ApiModelProperty(value = "mapper")
    private M baseMapper;
    @ApiModelProperty(value = "数据id")
    private Long id;
    @ApiModelProperty(value = "操作人id")
    private Long userId;
    @ApiModelProperty(value = "业务表实体类")
    private Class<T> entityClass;
    @ApiModelProperty(value = "业务数据")
    private T data;
    @ApiModelProperty(value = "当前节点id")
    private String curNodeId;
    @ApiModelProperty(value = "流程")
    private WorkFlow workFlow;
    @ApiModelProperty(value = "公司所有人员")
    private List<Long> companyUsers = new ArrayList<>();
    @ApiModelProperty(value = "当前节点的所有符合条件的审批人id")
    private List<Long> userIds = new ArrayList<>();
    @ApiModelProperty(value = "当审批索引")
    private Long curCheckIndex = 0L;
    @ApiModelProperty(value = "当前操作是否为提交")
    private Boolean isBegin = false;

    public WorkFlowUtil() {
    }

    /**
     * 构造函数
     * @param id 业务数据id
     * @param userId 用户id
     * @param entityClass 业务表实体类
     */
    public WorkFlowUtil(Long id, Long userId, Class<T> entityClass){
        this.id = id;
        this.userId = userId;
        this.entityClass = entityClass;
        setCurNodeAndFlow();
    }

    /**
     * 构造函数
     * @param id 业务数据id
     * @param userId 用户id
     * @param entityClass 业务表实体类
     * @param baseMapper 业务表mapper
     */
    public WorkFlowUtil(Long id, Long userId, Class<T> entityClass, M baseMapper){
        this.id = id;
        this.userId = userId;
        this.entityClass = entityClass;
        this.baseMapper = baseMapper;
        setCurNodeAndFlow();
    }

    /**
     * 获取当前节点id和流程
     */
    private void setCurNodeAndFlow(){
        // 查询数据
        T data = (T) this.baseMapper!=null?baseMapper.selectById(id):(T) getDataByClass(id);
        if (data == null) throw new CommonException("业务数据（id:" + id + "）不存在");
        this.data = data;
        // 流程
        Object workFlowObj = getGetMethod(data, "flow_json");
        if (workFlowObj == null) throw new CommonException("流程json不存在");
        this.workFlow = JSON.parseObject(String.valueOf(workFlowObj), WorkFlow.class);
        // 当前节点
        Object curNodeIdObj = getGetMethod(data, "flow_current_node_id");
        if (curNodeIdObj == null) throw new CommonException("当前节点id不存在");
        this.curNodeId = String.valueOf(curNodeIdObj);
    }

    private void copyDataToWfData(WFData wfData, WorkFlowNode node){
        wfData.setTitle(data.getFlow_title());
        wfData.setWork_flow_default_id(data.getFlow_default_id());
        wfData.setData_id(id);
        wfData.setStatus(0);
        wfData.setNode_id(node.getId());
        wfData.setNode_name(node.getName());
        wfData.setApplyer_id(data.getFlow_applyer_id());
        User user = workFlowUtil.userService.getById(data.getFlow_applyer_id());
        wfData.setApplyer_name(user != null ? user.getName() : "");
        wfData.setApplyer_department_id(data.getFlow_applyer_org_id());
        Department department = workFlowUtil.departmentService.getById(data.getFlow_applyer_org_id());
        wfData.setApplyer_department_name(department != null ? department.getName() : "");
    }

    /**
     * 开始审批
     * @param wfDataId 0：新建流程     !0：重新提交的流程
     * @param signUrl 签名路径
     * @return 1:成功
     */
    @Transactional
    public int Begin(Long wfDataId, String signUrl, T old_data){
        // 因为存在退回重新提交的情况，所以此处需要判断是否已有wf_data，
        //  已有的情况下，更新wf_data，toNext时的curCheckIndex参数用json中起始节点的cur_check_index
        //  没有的情况下，插入新的wf_data，toNext时的curCheckIndex参数用0

        // 当前操作是提交
        isBegin = true;

        //获取开始节点
        WorkFlowNode startNode = getStartNode(workFlow);
        if (startNode == null) throw new CommonException("审批流程不存在开始节点，请联系管理员");

        //判断是否为重新提交情况
        WFData temp = (wfDataId == 0L)?null:workFlowUtil.wfDataService.getById(wfDataId);
        WFData wfData = new WFData();

        // 反射获取实体类对应数据表名
        boolean clzHasAnno = entityClass.isAnnotationPresent(TableName.class);
        if (clzHasAnno) {
            // 获取类上的注解
            TableName tableName = entityClass.getAnnotation(TableName.class);
            // 输出注解上的属性
            wfData.setData_table(tableName.value());
        }


        Timestamp now = DateUtil.getTimeTimestamp();
        if (temp == null) {
            //新建数据
            copyDataToWfData(wfData, startNode);
            wfData.setCreate_at(now);
            wfData.setFlow_at(now);
            workFlowUtil.wfDataService.save(wfData);
            return ToNext(new WorkFlowCheckDTO(wfData.getNode_id(), 0L, null, signUrl, JSONObject.toJSONString(old_data)));
        }
        else {
            // 在草稿箱、回收站、被退回中删除该dataId
            workFlowUtil.wfDataDraftService.remove(new QueryWrapper<WFDataDraft>().eq("wf_data_id", temp.getId()));
            workFlowUtil.wfDataDeleteService.remove(new QueryWrapper<WFDataDelete>().eq("wf_data_id", temp.getId()));
            workFlowUtil.wfDataBackService.remove(new QueryWrapper<WFDataBack>().eq("wf_data_id", temp.getId()));
            //重新提交，更新WFData
            BeanUtils.copyProperties(temp, wfData);
            copyDataToWfData(wfData, startNode);
            wfData.setFlow_at(now);
            workFlowUtil.wfDataService.updateById(temp);
            return ToNext(new WorkFlowCheckDTO(temp.getNode_id(), startNode.getCur_check_index(), null, signUrl, JSONObject.toJSONString(old_data)));
        }
    }

    /**
     * 工作流_通过操作，流转至下一节点
     *
     * @param workFlowCheckDTO 审批数据对象
     * @return 1:流程中  2:通过
     */
    @Transactional
    public int ToNext(WorkFlowCheckDTO workFlowCheckDTO) {
        int returnInt = 1;

        // 设置当前审批轮次索引
        this.curCheckIndex = workFlowCheckDTO.getCurCheckIndex();

        // 检查数据的当前节点与审批节点是否一致
        checkNodeId(workFlowCheckDTO.getCheckNodeId());

        // 检验当前操作人合法性
        if (!isBegin && !userCanOperate()) throw new CommonException("当前操作人不合法！");

        // 下一节点
        String nextNodeId = getNextNodeId(curNodeId);

        // 将审批记录插入wf_check
        WFCheck wfCheck = insertWFCheck(workFlowCheckDTO, isBegin ? 0 : 1, curCheckIndex);

        // 修改属性workFlow
        updateWorkFlow(wfCheck.getId());

        // 获取wf_data
        WFData wfData = getWFData();

        // 拼装更新的wf_data对象
        WFData _wfData = new WFData();
        _wfData.setId(wfData.getId());
        _wfData.setCheck_id(wfCheck.getId());

        // 拼装更新的业务数据对象
//        T _data = entityClass.newInstance();
        T _data = null;
        try{
            _data = entityClass.newInstance();
        }catch (Exception e){
            log.error("业务数据对象创建失败", e);
            throw new CommonException("流程流转失败");
        }

        _data.setId(data.getId());
        _data.setFlow_json(JSON.toJSONString(workFlow));
        _data.setFlow_current_node_id(curNodeId);
        WorkFlowNode curNode = getNodeByNodeId(workFlow,curNodeId);
        if(curNode != null) _data.setFlow_current_node_name(curNode.getName());

        WorkFlowNode nextNode = null;
        WorkFlowDefault wfd = workFlowUtil.workFlowDefaultService.getById(data.getFlow_default_id());

        // 流转与否
        if (nextNodeId != null) {
            // nextNodeId不为null时流转至下一个节点
            _data.setFlow_current_node_id(nextNodeId);
            //保存当前节点为流转后的上一节点
            if (wfData.getPrev_node_id() == null || wfData.getPrev_node_id().length() == 0)
                _wfData.setPrev_node_id(wfData.getNode_id());
            else _wfData.setPrev_node_id(wfData.getPrev_node_id() + "," + wfData.getNode_id());

            nextNode = getNodeByNodeId(workFlow, nextNodeId);
            if (nextNode == null) throw new CommonException("下一节点不存在");
            _data.setFlow_current_node_name(nextNode.getName() != null ? nextNode.getName() : "");
            _wfData.setNode_id(nextNodeId);
            _wfData.setNode_name(nextNode.getName() != null ? nextNode.getName() : "");
            _wfData.setFlow_at(new Timestamp(System.currentTimeMillis()));
            _wfData.setCheck_id(wfCheck.getId());

            if (wfData.getStatus() == 0 || wfData.getStatus() == 1 || wfData.getStatus() == 3 || wfData.getStatus() == 4) {
                WFDataProcessing process = workFlowUtil.wfDataProcessingService.getOne(new QueryWrapper<WFDataProcessing>().eq("wf_data_id", _wfData.getId()));
                WFDataFinished finished = workFlowUtil.wfDataFinishedService.getOne(new QueryWrapper<WFDataFinished>().eq("wf_data_id", _wfData.getId()));
                if (nextNode.getType().equals("end")) {
                    _wfData.setStatus(2);
                    _data.setFlow_status(4);
                    _data.setFlow_passed_at(LocalDateTime.now());
                    returnInt = 2;
                    if (process != null) workFlowUtil.wfDataProcessingService.remove(new QueryWrapper<WFDataProcessing>().eq("wf_data_id", _wfData.getId()));
                    if (finished == null) {
                        WFDataFinished _finished = new WFDataFinished(_wfData.getId());
                        setWFDataSnapshot(_wfData, wfData, _finished);
                        workFlowUtil.wfDataFinishedService.save(_finished);

                        WFDataProcessingLog _proLog = new WFDataProcessingLog(_wfData.getId());
                        BeanUtils.copyProperties(_finished, _proLog);
                        if(curNode != null){
                            _proLog.setNode_id(curNode.getId());
                            _proLog.setNode_name(curNode.getName());
                        }else {
                            _proLog.setNode_id("");
                            _proLog.setNode_name("");
                        }
                        workFlowUtil.wfDataProcessingLogService.save(_proLog);

                        // 对提交人推送已通过的消息
                        workFlowUtil.messageCenterService.genFlowMessage(wfData.getApplyer_id(),wfd.getFlow_type(),_wfData.getId(),data.getId(),2);
                    }
                } else if (nextNode.getType().equals("check")) {
                    _wfData.setStatus(1);
                    _data.setFlow_status(3);

                    WFDataProcessing _process = new WFDataProcessing(_wfData.getId());
                    setWFDataSnapshot(_wfData, wfData, _process);
                    if (process != null) workFlowUtil.wfDataProcessingService.remove(new QueryWrapper<WFDataProcessing>().eq("wf_data_id", _wfData.getId()));
                    workFlowUtil.wfDataProcessingService.save(_process);

                    WFDataProcessingLog _proLog = new WFDataProcessingLog(_wfData.getId());
                    BeanUtils.copyProperties(_process, _proLog);
                    if(curNode != null){
                        _proLog.setNode_id(curNode.getId());
                        _proLog.setNode_name(curNode.getName());
                    }else {
                        _proLog.setNode_id("");
                        _proLog.setNode_name("");
                    }
                    workFlowUtil.wfDataProcessingLogService.save(_proLog);

                    if (finished != null) {
                        workFlowUtil.wfDataFinishedService.remove(new QueryWrapper<WFDataFinished>().eq("wf_data_id", _wfData.getId()));
                    }
                }
            } else throw new CommonException("wf_data状态不是流程中，无法通过");
        }else{
            log.error("下一节点为空");
        }
        // 业务数据更新
        updateData(_data);
        // 工作流上层表更新
        workFlowUtil.wfDataService.updateById(_wfData);
        // 更新wf_check表的wf_data_id
        workFlowUtil.wfCheckService.updateById(new WFCheck(wfCheck.getId(),_wfData.getId()));
        // 更新可审批人
        updateWFCurChecker(_wfData.getId());

        // 对下一节点的前置传阅人推送消息
        if(nextNode != null){
            List<String> nextNodePrevReaderIds = nextNode.getNodePrevReadersValue();
            if(CollectionUtils.isNotEmpty(nextNodePrevReaderIds)){
                for(String readerId: nextNodePrevReaderIds){
                    workFlowUtil.messageCenterService.genFlowMessage(Long.valueOf(readerId),wfd.getFlow_type(),_wfData.getId(),data.getId(),4);
                }
            }
        }
        // 对当前节点的后置传阅人推送消息
        if(curNode != null){
            List<String> afterNodePrevReaderIds = nextNode.getNodeAfterReadersValue();
            if(CollectionUtils.isNotEmpty(afterNodePrevReaderIds)){
                for(String readerId: afterNodePrevReaderIds){
                    workFlowUtil.messageCenterService.genFlowMessage(Long.valueOf(readerId),wfd.getFlow_type(),_wfData.getId(),data.getId(),4);
                }
            }
        }

        return returnInt;
    }

    /**
     * 工作流_通过操作，流转至下一节点
     *
     * @param workFlowCheckDTO 审批数据对象
     * @return 1:流程中  2:通过
     */
    @Transactional
    public int ToNext(WorkFlowCheckDTO workFlowCheckDTO, boolean isLinkDataOk) {
        int returnInt = 1;

        // 设置当前审批轮次索引
        this.curCheckIndex = workFlowCheckDTO.getCurCheckIndex();

        // 检查数据的当前节点与审批节点是否一致
        checkNodeId(workFlowCheckDTO.getCheckNodeId());

        // 检验当前操作人合法性
        if (!isBegin && !userCanOperate()) throw new CommonException("当前操作人不合法！");

        // 下一节点
        String nextNodeId = getNextNodeId(curNodeId);

        // 将审批记录插入wf_check
        WFCheck wfCheck = insertWFCheck(workFlowCheckDTO, isBegin ? 0 : 1, curCheckIndex);

        // 修改属性workFlow
        updateWorkFlow(wfCheck.getId());

        // 获取wf_data
        WFData wfData = getWFData();

        // 拼装更新的wf_data对象
        WFData _wfData = new WFData();
        _wfData.setId(wfData.getId());
        _wfData.setCheck_id(wfCheck.getId());

        // 拼装更新的业务数据对象
//        T _data = entityClass.newInstance();
        T _data = null;
        try{
            _data = entityClass.newInstance();
        }catch (Exception e){
            log.error("业务数据对象创建失败", e);
            throw new CommonException("流程流转失败");
        }

        _data.setId(data.getId());
        _data.setFlow_json(JSON.toJSONString(workFlow));
        _data.setFlow_current_node_id(curNodeId);
        WorkFlowNode curNode = getNodeByNodeId(workFlow,curNodeId);
        if(curNode != null) _data.setFlow_current_node_name(curNode.getName());

        WorkFlowNode nextNode = null;
        WorkFlowDefault wfd = workFlowUtil.workFlowDefaultService.getById(data.getFlow_default_id());

        // 流转与否
        if (nextNodeId != null) {
            // nextNodeId不为null时流转至下一个节点
            _data.setFlow_current_node_id(nextNodeId);
            //保存当前节点为流转后的上一节点
            if (wfData.getPrev_node_id() == null || wfData.getPrev_node_id().length() == 0)
                _wfData.setPrev_node_id(wfData.getNode_id());
            else _wfData.setPrev_node_id(wfData.getPrev_node_id() + "," + wfData.getNode_id());

            nextNode = getNodeByNodeId(workFlow, nextNodeId);
            if (nextNode == null) throw new CommonException("下一节点不存在");
            _data.setFlow_current_node_name(nextNode.getName() != null ? nextNode.getName() : "");
            _wfData.setNode_id(nextNodeId);
            _wfData.setNode_name(nextNode.getName() != null ? nextNode.getName() : "");
            _wfData.setFlow_at(new Timestamp(System.currentTimeMillis()));
            _wfData.setCheck_id(wfCheck.getId());

            if (wfData.getStatus() == 0 || wfData.getStatus() == 1 || wfData.getStatus() == 3 || wfData.getStatus() == 4) {
                WFDataProcessing process = workFlowUtil.wfDataProcessingService.getOne(new QueryWrapper<WFDataProcessing>().eq("wf_data_id", _wfData.getId()));
                WFDataFinished finished = workFlowUtil.wfDataFinishedService.getOne(new QueryWrapper<WFDataFinished>().eq("wf_data_id", _wfData.getId()));
                if (nextNode.getType().equals("end")) {
                    //最后一步，解决销售单未审核完成先要审核市场单的情况
                    if (isLinkDataOk) return -1;
                    _wfData.setStatus(2);
                    _data.setFlow_status(4);
                    _data.setFlow_passed_at(LocalDateTime.now());
                    returnInt = 2;
                    if (process != null) workFlowUtil.wfDataProcessingService.remove(new QueryWrapper<WFDataProcessing>().eq("wf_data_id", _wfData.getId()));
                    if (finished == null) {
                        WFDataFinished _finished = new WFDataFinished(_wfData.getId());
                        setWFDataSnapshot(_wfData, wfData, _finished);
                        workFlowUtil.wfDataFinishedService.save(_finished);

                        WFDataProcessingLog _proLog = new WFDataProcessingLog(_wfData.getId());
                        BeanUtils.copyProperties(_finished, _proLog);
                        if(curNode != null){
                            _proLog.setNode_id(curNode.getId());
                            _proLog.setNode_name(curNode.getName());
                        }else {
                            _proLog.setNode_id("");
                            _proLog.setNode_name("");
                        }
                        workFlowUtil.wfDataProcessingLogService.save(_proLog);

                        // 对提交人推送已通过的消息
                        workFlowUtil.messageCenterService.genFlowMessage(wfData.getApplyer_id(),wfd.getFlow_type(),_wfData.getId(),data.getId(),2);
                    }
                } else if (nextNode.getType().equals("check")) {
                    _wfData.setStatus(1);
                    _data.setFlow_status(3);

                    WFDataProcessing _process = new WFDataProcessing(_wfData.getId());
                    setWFDataSnapshot(_wfData, wfData, _process);
                    if (process != null) workFlowUtil.wfDataProcessingService.remove(new QueryWrapper<WFDataProcessing>().eq("wf_data_id", _wfData.getId()));
                    workFlowUtil.wfDataProcessingService.save(_process);

                    WFDataProcessingLog _proLog = new WFDataProcessingLog(_wfData.getId());
                    BeanUtils.copyProperties(_process, _proLog);
                    if(curNode != null){
                        _proLog.setNode_id(curNode.getId());
                        _proLog.setNode_name(curNode.getName());
                    }else {
                        _proLog.setNode_id("");
                        _proLog.setNode_name("");
                    }
                    workFlowUtil.wfDataProcessingLogService.save(_proLog);

                    if (finished != null) {
                        workFlowUtil.wfDataFinishedService.remove(new QueryWrapper<WFDataFinished>().eq("wf_data_id", _wfData.getId()));
                    }
                }
            } else throw new CommonException("wf_data状态不是流程中，无法通过");
        }else{
            log.error("下一节点为空");
        }
        // 业务数据更新
        updateData(_data);
        // 工作流上层表更新
        workFlowUtil.wfDataService.updateById(_wfData);
        // 更新wf_check表的wf_data_id
        workFlowUtil.wfCheckService.updateById(new WFCheck(wfCheck.getId(),_wfData.getId()));
        // 更新可审批人
        updateWFCurChecker(_wfData.getId());

        // 对下一节点的前置传阅人推送消息
        if(nextNode != null){
            List<String> nextNodePrevReaderIds = nextNode.getNodePrevReadersValue();
            if(CollectionUtils.isNotEmpty(nextNodePrevReaderIds)){
                for(String readerId: nextNodePrevReaderIds){
                    workFlowUtil.messageCenterService.genFlowMessage(Long.valueOf(readerId),wfd.getFlow_type(),_wfData.getId(),data.getId(),4);
                }
            }
        }
        // 对当前节点的后置传阅人推送消息
        if(curNode != null){
            List<String> afterNodePrevReaderIds = nextNode.getNodeAfterReadersValue();
            if(CollectionUtils.isNotEmpty(afterNodePrevReaderIds)){
                for(String readerId: afterNodePrevReaderIds){
                    workFlowUtil.messageCenterService.genFlowMessage(Long.valueOf(readerId),wfd.getFlow_type(),_wfData.getId(),data.getId(),4);
                }
            }
        }

        return returnInt;
    }

    /**
     * 工作流_强制退回操作，不校验审批人，退回至提交人处，需重新提交
     *
     * @param workFlowCheckDTO 审批数据对象
     * @return 1:成功
     */
    public int ReturnBackForce(WorkFlowCheckDTO workFlowCheckDTO){
        return ReturnBack(workFlowCheckDTO, true);
    }

    /**
     * 工作流_退回操作，退回至提交人处，需重新提交
     *
     * @param workFlowCheckDTO 审批数据对象
     * @return 1:成功
     */
    @Transactional
    public int ReturnBack(WorkFlowCheckDTO workFlowCheckDTO,boolean ...notCheckChecker){
        // 设置当前审批轮次索引
        this.curCheckIndex = workFlowCheckDTO.getCurCheckIndex();

        // 检查数据的当前节点与审批节点是否一致

        checkNodeId(workFlowCheckDTO.getCheckNodeId());

        // 检验当前操作人合法性
        if (notCheckChecker==null || notCheckChecker.length!=1 || !notCheckChecker[0]){
            if (!userCanOperate()) {
                throw new CommonException("当前操作人不合法！");
            }
        }


        // 将审批记录插入wf_check
        WFCheck wfCheck = insertWFCheck(workFlowCheckDTO, 2, curCheckIndex);

        WorkFlowNode curNode = getNodeByNodeId(workFlow,curNodeId);

        // 修改属性workFlow
        updateWorkFlow(wfCheck.getId(), true);

        // 获取wf_data
        WFData wfData = getWFData();

        // 拼装更新的wf_data对象
        WFData _wfData = new WFData();
        _wfData.setId(wfData.getId());
        _wfData.setCheck_id(wfCheck.getId());

        // 拼装更新的业务数据对象
        T _data = null;
        try{
            _data = entityClass.newInstance();
        }catch (Exception e){
            log.error("业务数据对象创建失败", e);
            throw new CommonException("流程流转失败");
        }
        _data.setId(data.getId());


        // 退回到起始节点
        WorkFlowNode startNode = getStartNode(workFlow);
        if (startNode == null) throw new CommonException("出错，起始节点不存在");
        startNode.setCur_check_index(startNode.getCur_check_index() + 1);

        _data.setFlow_json(JSON.toJSONString(workFlow));
        _data.setFlow_current_node_id(startNode.getId());
        _data.setFlow_current_node_name(startNode.getName() != null ? startNode.getName() : "");

        _wfData.setNode_id(startNode.getId());
        _wfData.setNode_name(startNode.getName() != null ? startNode.getName() : "");
        _wfData.setFlow_at(new Timestamp(System.currentTimeMillis()));
        _wfData.setCheck_id(wfCheck.getId());
        _wfData.setStatus(4);

        _data.setFlow_status(2);

        WFDataBack _back = new WFDataBack(_wfData.getId());
        setWFDataSnapshot(_wfData, wfData, _back);
        workFlowUtil.wfDataBackService.save(_back);

        WFDataProcessingLog _proLog = new WFDataProcessingLog(_wfData.getId());
        BeanUtils.copyProperties(_back, _proLog);
        if(curNode != null){
            _proLog.setNode_id(curNode.getId());
            _proLog.setNode_name(curNode.getName());
        }else {
            _proLog.setNode_id("");
            _proLog.setNode_name("");
        }
        workFlowUtil.wfDataProcessingLogService.save(_proLog);

        workFlowUtil.wfDataProcessingService.remove(new QueryWrapper<WFDataProcessing>().eq("wf_data_id", _wfData.getId()));

        // 业务数据更新
        // 业务数据更新
        updateData(_data);
        // 工作流上层表更新
        workFlowUtil.wfDataService.updateById(_wfData);
        // 更新wf_check表的wf_data_id
        workFlowUtil.wfCheckService.updateById(new WFCheck(wfCheck.getId(),_wfData.getId()));
        // 删除可审批人
        deleteWFCurChecker(_wfData.getId());
        // 对提交人推送被退回的消息
        WorkFlowDefault wfd = workFlowUtil.workFlowDefaultService.getById(data.getFlow_default_id());
        workFlowUtil.messageCenterService.genFlowMessage(wfData.getApplyer_id(),wfd.getFlow_type(),_wfData.getId(),data.getId(),3);

        return 1;
    }

    /**
     * 工作流_重审操作，退回至上一个节点，需上个节点的审批人重新审批
     *
     * @param workFlowCheckDTO 审批数据对象
     * @return 1:成功
     */
    @Transactional
    public int ReturnPrev(WorkFlowCheckDTO workFlowCheckDTO){
        // 设置当前审批轮次索引
        this.curCheckIndex = workFlowCheckDTO.getCurCheckIndex();

        // 检查数据的当前节点与审批节点是否一致
        checkNodeId(workFlowCheckDTO.getCheckNodeId());

        // 检验当前操作人合法性
        if (!userCanOperate()) {
            throw new CommonException("当前操作人不合法！");
        }

        // 将审批记录插入wf_check
        WFCheck wfCheck = insertWFCheck(workFlowCheckDTO, 3, curCheckIndex);

        WorkFlowNode curNode = getNodeByNodeId(workFlow,curNodeId);

        // 修改属性workFlow
        updateWorkFlow(wfCheck.getId(), true);

        // 获取wf_data
        WFData wfData = getWFData();

        // 拼装更新的wf_data对象
        WFData _wfData = new WFData();
        _wfData.setId(wfData.getId());
        _wfData.setCheck_id(wfCheck.getId());

        // 拼装更新的业务数据对象
        T _data = null;
        try{
            _data = entityClass.newInstance();
        }catch (Exception e){
            log.error("业务数据对象创建失败", e);
            throw new CommonException("流程流转失败");
        }
        _data.setId(data.getId());


        // 退回到前一节点
        String[] prev_nodes_temp = wfData.getPrev_node_id().split(",");
        WorkFlowNode prevNode = getNodeByNodeId(workFlow, prev_nodes_temp[prev_nodes_temp.length - 1]);
        if (prevNode == null) throw new CommonException("出错，前一节点不存在");

        _data.setFlow_json(JSON.toJSONString(workFlow));
        _data.setFlow_current_node_id(prevNode.getId());
        _data.setFlow_current_node_name(prevNode.getName() != null ? prevNode.getName() : "");

        _wfData.setNode_id(prevNode.getId());
        _wfData.setNode_name(prevNode.getName() != null ? prevNode.getName() : "");
        _wfData.setFlow_at(new Timestamp(System.currentTimeMillis()));
        _wfData.setCheck_id(wfCheck.getId());


        prev_nodes_temp = wfData.getPrev_node_id().split(",");
        String prev_node = new String();
        for (int i = 0; i < prev_nodes_temp.length - 1; i++) {
            prev_node += prev_nodes_temp[i];
            prev_node += ",";
        }
        if (prev_node.length() > 0) {
            prev_node = prev_node.substring(0, prev_node.length() - 1);
        }
        _wfData.setPrev_node_id(prev_node);

        if (prevNode.getType().equals("start")) {
            _wfData.setStatus(4);
            _data.setFlow_status(2);
            workFlowUtil.wfDataProcessingService.remove(new QueryWrapper<WFDataProcessing>().eq("wf_data_id", _wfData.getId()));
            WFDataBack _back = new WFDataBack(_wfData.getId());
            setWFDataSnapshot(_wfData, wfData, _back);
            workFlowUtil.wfDataBackService.save(_back);

            WFDataProcessingLog _proLog = new WFDataProcessingLog(_wfData.getId());
            BeanUtils.copyProperties(_back, _proLog);
            if(curNode != null){
                _proLog.setNode_id(curNode.getId());
                _proLog.setNode_name(curNode.getName());
            }else {
                _proLog.setNode_id("");
                _proLog.setNode_name("");
            }
            workFlowUtil.wfDataProcessingLogService.save(_proLog);
        }

        // 业务数据更新
        updateData(_data);
        // 工作流上层表更新
        workFlowUtil.wfDataService.updateById(_wfData);
        // 更新wf_check表的wf_data_id
        workFlowUtil.wfCheckService.updateById(new WFCheck(wfCheck.getId(),_wfData.getId()));
        // 更新可审批人
        updateWFCurChecker(_wfData.getId());

        // todo 对重审节点的审批人推送重审消息
        return 1;
    }

    /**
     * 保存至草稿箱
     * @param wfDataId 在“已删除”、“被退回”中，保存至草稿箱，须将原wfDataId传入
     * @return 1:成功
     */
    @Transactional
    public int SaveDraft(Long ... wfDataId){
        // wf_data
        WFData wfData = new WFData();

        //获取开始节点
        WorkFlowNode startNode = getStartNode(workFlow);
        if (startNode == null) throw new CommonException("审批流程不存在开始节点，请联系管理员");

        // 反射获取实体类对应数据表名
        boolean clzHasAnno = entityClass.isAnnotationPresent(TableName.class);
        if (clzHasAnno) {
            // 获取类上的注解
            TableName tableName = entityClass.getAnnotation(TableName.class);
            // 输出注解上的属性
            wfData.setData_table(tableName.value());
        }

        //新建数据
        copyDataToWfData(wfData, startNode);
        wfData.setCreate_at(DateUtil.getTimeTimestamp());
        workFlowUtil.wfDataService.save(wfData);

        T _data = null;
        try{
            _data = entityClass.newInstance();
        }catch (Exception e){
            log.error("业务数据对象创建失败", e);
            throw new CommonException("流程流转失败");
        }

        // 在 已删除、被退回、流程中、已通过、草稿箱 中删除该dataId
        if(wfDataId != null && wfDataId.length == 1){ // 原wfData
            workFlowUtil.wfDataService.remove(new QueryWrapper<WFData>().eq("id", wfDataId[0]));
            workFlowUtil.wfDataDeleteService.remove(new QueryWrapper<WFDataDelete>().eq("wf_data_id", wfDataId[0]));
            workFlowUtil.wfDataBackService.remove(new QueryWrapper<WFDataBack>().eq("wf_data_id", wfDataId[0]));
            workFlowUtil.wfDataProcessingService.remove(new QueryWrapper<WFDataProcessing>().eq("wf_data_id", wfDataId[0]));
            workFlowUtil.wfDataFinishedService.remove(new QueryWrapper<WFDataFinished>().eq("wf_data_id", wfDataId[0]));
            workFlowUtil.wfDataDraftService.remove(new QueryWrapper<WFDataDraft>().eq("wf_data_id", wfDataId[0]));
        }
        workFlowUtil.wfDataDeleteService.remove(new QueryWrapper<WFDataDelete>().eq("wf_data_id", wfData.getId()));
        workFlowUtil.wfDataBackService.remove(new QueryWrapper<WFDataBack>().eq("wf_data_id", wfData.getId()));
        workFlowUtil.wfDataProcessingService.remove(new QueryWrapper<WFDataProcessing>().eq("wf_data_id", wfData.getId()));
        workFlowUtil.wfDataFinishedService.remove(new QueryWrapper<WFDataFinished>().eq("wf_data_id", wfData.getId()));
        workFlowUtil.wfDataDraftService.remove(new QueryWrapper<WFDataDraft>().eq("wf_data_id", wfData.getId()));

        _data.setId(data.getId());
        WFDataDraft _draft = new WFDataDraft(wfData.getId());
        BeanUtils.copyProperties(wfData, _draft);
        workFlowUtil.wfDataDraftService.save(_draft);

//        WFDataProcessingLog _proLog = new WFDataProcessingLog(wfData.getId());
//        BeanUtils.copyProperties(_draft, _proLog);
//        workFlowUtil.wfDataProcessingLogService.save(_proLog);

        _data.setFlow_status(0);
        // 业务数据更新
        updateData(_data);
        // 删除可审批人
        deleteWFCurChecker(wfData.getId());


        return 1;
    }

    /**
     * 工作流_删除操作
     * @param wfDataId 在“草稿箱”、“被退回”中，进行删除，须将原wfDataId传入
     * @return 1:成功
     */
    @Transactional
    public int Delete(Long ... wfDataId){

        // 获取wf_data
        WFData wfData = getWFData();

        // 拼装更新的wf_data对象
        WFData _wfData = new WFData();
        _wfData.setId(wfData.getId());
        _wfData.setStatus(3);

        T _data = null;
        try{
            _data = entityClass.newInstance();
        }catch (Exception e){
            log.error("业务数据对象创建失败", e);
            throw new CommonException("流程流转失败");
        }

        _data.setId(data.getId());

        WorkFlowNode curNode = getNodeByNodeId(workFlow,curNodeId);

        // 在 已删除、被退回、流程中、已通过、草稿箱 中删除该dataId
        if(wfDataId != null && wfDataId.length == 1){ // 原wfData
            workFlowUtil.wfDataDeleteService.remove(new QueryWrapper<WFDataDelete>().eq("wf_data_id", wfDataId[0]));
            workFlowUtil.wfDataBackService.remove(new QueryWrapper<WFDataBack>().eq("wf_data_id", wfDataId[0]));
            workFlowUtil.wfDataProcessingService.remove(new QueryWrapper<WFDataProcessing>().eq("wf_data_id", wfDataId[0]));
            workFlowUtil.wfDataFinishedService.remove(new QueryWrapper<WFDataFinished>().eq("wf_data_id", wfDataId[0]));
            workFlowUtil.wfDataDraftService.remove(new QueryWrapper<WFDataDraft>().eq("wf_data_id", wfDataId[0]));
        }
        workFlowUtil.wfDataDeleteService.remove(new QueryWrapper<WFDataDelete>().eq("wf_data_id", _wfData.getId()));
        workFlowUtil.wfDataBackService.remove(new QueryWrapper<WFDataBack>().eq("wf_data_id", _wfData.getId()));
        workFlowUtil.wfDataProcessingService.remove(new QueryWrapper<WFDataProcessing>().eq("wf_data_id", _wfData.getId()));
        workFlowUtil.wfDataFinishedService.remove(new QueryWrapper<WFDataFinished>().eq("wf_data_id", _wfData.getId()));
        workFlowUtil.wfDataDraftService.remove(new QueryWrapper<WFDataDraft>().eq("wf_data_id", _wfData.getId()));

        WFDataDelete _delete = new WFDataDelete(_wfData.getId());
        setWFDataSnapshot(_wfData, wfData, _delete);
        workFlowUtil.wfDataDeleteService.save(_delete);

        WFDataProcessingLog _proLog = new WFDataProcessingLog(_wfData.getId());
        BeanUtils.copyProperties(_delete, _proLog);
        if(curNode != null){
            _proLog.setNode_id(curNode.getId());
            _proLog.setNode_name(curNode.getName());
        }else {
            _proLog.setNode_id("");
            _proLog.setNode_name("");
        }
        workFlowUtil.wfDataProcessingLogService.save(_proLog);

        _data.setFlow_status(5);

        // 业务数据更新
        updateData(_data);
        // 工作流上层表更新
        workFlowUtil.wfDataService.updateById(_wfData);
        // 删除可审批人
        deleteWFCurChecker(_wfData.getId());

        return 1;
    }

    /**
     * 工作流_完全删除操作，在wf_data_delete中也不存在，完全脱出审批流程
     * @param wfDataId 原wfDataId
     * @return 1:成功
     */
    @Transactional
    public int ActualDelete(Long wfDataId){

        // 拼装更新的wf_data对象
        WFData _wfData = new WFData();
        _wfData.setId(wfDataId);
        _wfData.setStatus(3);

        T _data = null;
        try{
            _data = entityClass.newInstance();
        }catch (Exception e){
            log.error("业务数据对象创建失败", e);
            throw new CommonException("流程流转失败");
        }

        _data.setId(data.getId());

        // 在 已删除、被退回、流程中、已通过、草稿箱 中删除该dataId
        workFlowUtil.wfDataDeleteService.remove(new QueryWrapper<WFDataDelete>().eq("wf_data_id", _wfData.getId()));
        workFlowUtil.wfDataBackService.remove(new QueryWrapper<WFDataBack>().eq("wf_data_id", _wfData.getId()));
        workFlowUtil.wfDataProcessingService.remove(new QueryWrapper<WFDataProcessing>().eq("wf_data_id", _wfData.getId()));
        workFlowUtil.wfDataFinishedService.remove(new QueryWrapper<WFDataFinished>().eq("wf_data_id", _wfData.getId()));
        workFlowUtil.wfDataDraftService.remove(new QueryWrapper<WFDataDraft>().eq("wf_data_id", _wfData.getId()));

        _data.setDeleted_at(LocalDateTime.now());
        _data.setFlow_status(6);

        // 业务数据更新
        updateData(_data);
        // 工作流上层表更新
        workFlowUtil.wfDataService.updateById(_wfData);
        // 删除可审批人
        deleteWFCurChecker(_wfData.getId());

        return 1;
    }

    /**
     * 工作流_跳过余下审批，直接通过
     * @return 1:成功
     */
    @Transactional
    public int Passed(){

        // 获取wf_data
        WFData wfData = getWFData();

        // 拼装更新的wf_data对象
        WFData _wfData = new WFData();
        _wfData.setId(wfData.getId());
        _wfData.setStatus(2);

        WorkFlowNode curNode = getNodeByNodeId(workFlow,curNodeId);

        T _data = null;
        try{
            _data = entityClass.newInstance();
        }catch (Exception e){
            log.error("业务数据对象创建失败", e);
            throw new CommonException("流程流转失败");
        }

        _data.setId(data.getId());

        if (wfData.getStatus() == 0 || wfData.getStatus() == 1) {
            WFDataProcessing process = workFlowUtil.wfDataProcessingService.getOne(new QueryWrapper<WFDataProcessing>().eq("wf_data_id", _wfData.getId()));
            WFDataFinished finished = workFlowUtil.wfDataFinishedService.getOne(new QueryWrapper<WFDataFinished>().eq("wf_data_id", _wfData.getId()));
            if (process != null) {
                workFlowUtil.wfDataProcessingService.remove(new QueryWrapper<WFDataProcessing>().eq("wf_data_id", _wfData.getId()));
            }
            if (finished == null) {
                WFDataFinished _finished = new WFDataFinished(_wfData.getId());
                setWFDataSnapshot(_wfData, wfData, _finished);
                workFlowUtil.wfDataFinishedService.save(_finished);

                WFDataProcessingLog _proLog = new WFDataProcessingLog(_wfData.getId());
                BeanUtils.copyProperties(_finished, _proLog);
                if(curNode != null){
                    _proLog.setNode_id(curNode.getId());
                    _proLog.setNode_name(curNode.getName());
                }else {
                    _proLog.setNode_id("");
                    _proLog.setNode_name("");
                }
                workFlowUtil.wfDataProcessingLogService.save(_proLog);
            }
            _data.setFlow_status(4);
            _data.setFlow_passed_at(LocalDateTime.now());
        } else throw new CommonException("wf_data状态不是流程中，无法通过");

        // 业务数据更新
        updateData(_data);
        // 工作流上层表更新
        workFlowUtil.wfDataService.updateById(_wfData);
        // 删除可审批人
        deleteWFCurChecker(_wfData.getId());

        return 1;
    }

    /**
     * 设置快照数据属性
     */
    private <W extends WFDataSnapshotSuper> void setWFDataSnapshot(WFData new_wfData, WFData old_wfData , W data){
        BeanUtils.copyProperties(new_wfData, data);
        data.setTitle(old_wfData.getTitle());
        data.setWork_flow_default_id(old_wfData.getWork_flow_default_id());
        data.setData_table(old_wfData.getData_table());
        data.setData_id(old_wfData.getData_id());
        data.setApplyer_department_id(old_wfData.getApplyer_department_id());
        data.setApplyer_department_name(old_wfData.getApplyer_department_name());
        data.setApplyer_id(old_wfData.getApplyer_id());
        data.setApplyer_name(old_wfData.getApplyer_name());
    }

    /**
     * 校验当前人是否最后一个审批人
     * @return 1：是   0：否
     */
    public int NextIsEnd(WorkFlowCheckDTO workFlowCheckDTO){
        // 设置当前审批轮次索引
        this.curCheckIndex = workFlowCheckDTO.getCurCheckIndex();

        // 检查数据的当前节点与审批节点是否一致
        checkNodeId(workFlowCheckDTO.getCheckNodeId());

        // 检验当前操作人合法性
        if (!isBegin && !userCanOperate()) throw new CommonException("当前操作人不合法！");

        // 下一节点
        String nextNodeId = getNextNodeId(curNodeId);
        // 下一节点为空
        if(StringUtils.isEmpty(nextNodeId)) throw new CommonException("下一级节点不存在！");

        WorkFlowNode nextNode = getNodeByNodeId(workFlow,nextNodeId);
        if(nextNode == null) throw new CommonException("下一级节点不存在！");
        return nextNode.getType().equals("end")?1:0;
    }

    /**
     * 根据数据id查找流程id
     * @param data_id 数据id
     */
    public Long getWfDataId(Long data_id){
        if(data_id == null) throw new CommonException("请传入数据id！");
        // 数据表名称
        String data_table = null;
        // 反射获取实体类对应数据表名
        boolean clzHasAnno = entityClass.isAnnotationPresent(TableName.class);
        if (clzHasAnno) {
            // 获取类上的注解
            TableName tableName = entityClass.getAnnotation(TableName.class);
            // 输出注解上的属性
            data_table = tableName.value();
        }
        if(StringUtils.isEmpty(data_table)) throw new CommonException("反射出错，实体类无 @TableName 注解，请检查！");

        List<WFData> wfDataList = workFlowUtil.wfDataService.list(new QueryWrapper<WFData>().eq("data_table", data_table).eq("data_id", data_id).orderByDesc("create_at"));
        if(CollectionUtils.isEmpty(wfDataList)) throw new CommonException("流程不存在，请检查！");

        return wfDataList.get(0).getId();
    }

    /**
     * 校验当前人是否能审批，针对流程视图
     * @param userId 当前人
     * @param wfDatas 流程视图数据
     * @param <Y> VWFDataEntity的继承类
     */
    public static <T extends FlowBusinessDataSuperEntity, Y extends VWFDataEntity> void canCheckData(Long userId, List<Y> wfDatas){
        if(CollectionUtils.isNotEmpty(wfDatas)){
            for(Y wfData: wfDatas){
                T data = (T)getDataByTableName(wfData.getData_id(),wfData.getData_table());
                wfData.setCanCheck(canCheckData(userId, data));
            }
        }
    }

    private static <T extends FlowBusinessDataSuperEntity> Object getDataByTableName(Long id, String name) {
        try {
            Object mapperServiceBean = SpringContextUtil.getBean(StringChangeUtil.lineToHump(name)+"Mapper");
            Method mapperServiceBeanMethod = ReflectionUtils.findMethod(mapperServiceBean.getClass(), "selectById", Serializable.class);
            // 执行方法
            return ReflectionUtils.invokeMethod(mapperServiceBeanMethod, mapperServiceBean, id);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 校验当前人是否能审批该业务数据
     * @param userId 当前人id
     * @param data 业务数据（至少包含id、flow_status、flow_applyer_id、flow_applyer_org_id、flow_json、flow_current_node_id六个字段）
     * @return HashMap<id,flag>  flag true:需当前人审批  false:当前人无权限审批
     */
    public static <T extends FlowBusinessDataSuperEntity,R extends FlowBusinessDataSuperEntity> HashMap<Long, Boolean> canCheckData
            (Long userId, List<T> data, Class<R> entityClass){
        HashMap<Long, Boolean> returnMap = new HashMap<>();
        if(CollectionUtils.isNotEmpty(data)){
            for (T item : data) {
                if(StringUtils.isEmpty(item.getFlow_json())){
                    if(entityClass == null) throw new CommonException("请为实体对象设置流程相关参数，或传入实体类class");
                    FlowBusinessDataSuperEntity _data = (FlowBusinessDataSuperEntity) getDataByClass(item.getId(), entityClass);
                    if(_data != null) BeanUtils.copyProperties(_data, item);
                }
                if(item.getFlow_json() == null) {
                    returnMap.put(item.getId(), false);
                    continue;
                }
                if(item.getFlow_status() != 3) continue;
                returnMap.put(item.getId(), canCheckData(userId, item));
            }
        }
        return returnMap;
    }

    private static <T extends FlowBusinessDataSuperEntity> Object getDataByClass(Long id, Class<T> entityClass) {
        String dataPath = SqlHelper.table(entityClass).getCurrentNamespace();
        Class<?> mapperClass = null;
        try {
            mapperClass = Class.forName(dataPath);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            Object mapperServiceBean = SpringContextUtil.getBean(mapperClass);
            Method mapperServiceBeanMethod = ReflectionUtils.findMethod(mapperServiceBean.getClass(), "selectById", Serializable.class);
            // 执行方法
            return ReflectionUtils.invokeMethod(mapperServiceBeanMethod, mapperServiceBean, id);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 校验当前人是否能审批该业务数据
     * @param userId 当前人id
     * @param data   业务数据（至少包含flow_status、flow_applyer_id、flow_applyer_org_id、flow_json、flow_current_node_id五个字段）
     * @return true:需当前人审批  false:当前人无权限审批
     * @throws Exception 当前节点不存在、未传当前人id
     */
    public static <T extends FlowBusinessDataSuperEntity> boolean canCheckData(Long userId, T data){
        if(data.getFlow_status() != 3) return false;
        // 当前节点
        WorkFlowNode node = WorkFlowUtil.getNodeByNodeId(
                JSON.parseObject(data.getFlow_json(), WorkFlow.class)
                , data.getFlow_current_node_id());
        if(node == null) throw new CommonException("流程错误，当前节点不存在");

        if (node.getCheck_ids().size() > node.getCur_check_index()) {
            List<WorkFlowUserCheck> workFlowUserChecks = node.getCheck_ids().get(node.getCur_check_index().intValue());
            for (WorkFlowUserCheck workFlowUserCheck : workFlowUserChecks) {
                if (workFlowUserCheck.getUserId().equals(userId)) {
                    return false;
                }
            }
        }

        if (node.getNodeCanChooseSwitch() == 1) {
            // 将所有可选人存入节点的全部审批人
            for (String user : node.getNodeCanChooseValueSubmit()) {
                if (user.equals(Long.toString(userId))) {
                    return true;
                }
            }
            return false;
        }
        List<WorkFlowPropertyData> conditions = node.getData();
        if (conditions == null || conditions.size() == 0) {
            return false;
        }
        StringBuffer conditionJSStr = new StringBuffer();
        for (WorkFlowPropertyData condition : conditions) {
            conditionJSStr.append(getJSStrByCondition(data, condition, true, userId));
        }
        return generateConditionResult(conditionJSStr.toString());
    }

    /**
     * 查找起始节点
     */
    public static WorkFlowNode getStartNode(WorkFlow workFlow) {
        List<WorkFlowNode> nodeList = workFlow.getNodeList();
        for (WorkFlowNode node : nodeList) {
            if (node.getType().equals("start")) return node;
        }
        return null;
    }

    /**
     * 根据nodeId找出node
     */
    public static WorkFlowNode getNodeByNodeId(WorkFlow workFlow, String nodeId) {
        for (WorkFlowNode workFlowNode : workFlow.getNodeList()) {
            if (workFlowNode.getId().equals(nodeId)) return workFlowNode;
        }
        return null;
    }

    /**
     * 获取节点的审批轮次
     * @param flow_json 流程json
     * @param nodeId 节点
     * @return 审批伦次
     * @throws Exception 节点不存在
     */
    public static Long getCurCheckIndex(String flow_json, String nodeId){
        // 当前节点
        WorkFlowNode node = WorkFlowUtil.getNodeByNodeId(
                JSON.parseObject(flow_json, WorkFlow.class)
                , nodeId);
        if(node == null) throw new CommonException("流程错误，当前节点不存在");
        // 当前审批轮次
        return node.getCur_check_index();
    }

    /**
     * 组装超类流程字段
     * @param userId 用户id
     * @param departmentId 用户所在部门id
     * @param flow_type 流程类型
     * @param title 流程标题
     * @throws Exception 开始节点不存在
     */
    public static FlowBusinessDataSuperEntity getStartSuperDataEntity(Long userId, Long departmentId, Integer flow_type, String ...title){
        // 获取流程json
        WorkFlowDefault wfd = workFlowUtil.workFlowDefaultService.getActiveByFlowType(flow_type);
        // 获取开始节点
        WorkFlowNode startNode = WorkFlowUtil.getStartNode(JSON.parseObject(wfd.getFlow_json(), WorkFlow.class));
        if(startNode == null) throw new CommonException("流程错误，开始节点不存在");

        FlowBusinessDataSuperEntity fbdse = new FlowBusinessDataSuperEntity();
        fbdse.setFlow_title(title != null? (StringUtils.isNotEmpty(title[0])?title[0]:wfd.getName()):wfd.getName());
        fbdse.setFlow_applyer_id(userId);
        fbdse.setFlow_applyer_org_id(departmentId);
        fbdse.setFlow_json(wfd.getFlow_json());
        fbdse.setStatus(0);
        fbdse.setFlow_current_node_id(startNode.getId());
        fbdse.setFlow_default_id(wfd.getId());
        return fbdse;
    }

    /**
     * 删除业务数据的可审批人
     */
    private void deleteWFCurChecker(Long wfDataId){
        workFlowUtil.wfCurCheckerService.remove(new QueryWrapper<WFCurChecker>().eq("wf_data_id", wfDataId));
    }

    /**
     * 更新业务数据的可审批人
     */
    private void updateWFCurChecker(Long wfDataId){
        deleteWFCurChecker(wfDataId);
        T data = (T) baseMapper.selectById(id);
        WorkFlowDefault wfd = workFlowUtil.workFlowDefaultService.getById(data.getFlow_default_id());

        if(wfd != null) {
            List<User> users = workFlowUtil.userService.list(new QueryWrapper<User>().select("id").isNull("deleted_at").eq("status", 1));
            if(CollectionUtils.isNotEmpty(users)){
                List<Long> checkerIds = new ArrayList<>();
                if(CollectionUtils.isNotEmpty(users)){
                    checkerIds = users.stream().filter(u -> (canCheckData(u.getId(), data))).map(User::getId).collect(Collectors.toList());
                }
                if(CollectionUtils.isNotEmpty(checkerIds)){
                    List<WFCurChecker> checkers = checkerIds.stream().map(checkerId -> {
                        WFCurChecker temp = new WFCurChecker();
                        temp.setWf_data_id(wfDataId);
                        temp.setWork_flow_default_id(wfd.getId());
                        temp.setFlow_type(wfd.getFlow_type());
                        temp.setData_table(wfd.getData_table());
                        temp.setData_id(data.getId());
                        temp.setChecker_id(checkerId);
                        return temp;
                    }).collect(Collectors.toList());
                    if(CollectionUtils.isNotEmpty(checkers)){
                        workFlowUtil.wfCurCheckerService.saveBatch(checkers);
                        for(WFCurChecker checker: checkers){
                            workFlowUtil.messageCenterService.genFlowMessage(checker.getChecker_id(),wfd.getFlow_type(),wfDataId,data.getId(),1);
                        }
                    }
                }
            }
        }
    }

    /**
     * 将审批数据插入wf_check表
     */
    private WFCheck insertWFCheck(WorkFlowCheckDTO dto, Integer type, Long checkIndex) {
        String opinion = dto.getOpinion();
        String sign_url = dto.getSign_url();
        WorkFlowNode curNode = getNodeByNodeId(workFlow,curNodeId);
        WFCheck wfCheck = new WFCheck(data.getFlow_default_id(), id, curNodeId, curNode.getName(), checkIndex, userId,
                type, opinion, sign_url, dto.getData_json());
        workFlowUtil.wfCheckService.save(wfCheck);
        return wfCheck;
    }

    /**
     * 更新workFlow属性
     *
     * @param check_id 审批id
     * @param addIndex 审批伦次索引是否+1
     */
    private void updateWorkFlow(Long check_id, Boolean... addIndex){
        WorkFlowNode curNode = getNodeByNodeId(workFlow, curNodeId);
        if (curNode == null) {
            throw new CommonException("当前节点不存在");
        }
        List<List<WorkFlowUserCheck>> check_ids = curNode.getCheck_ids();
        WorkFlowUserCheck userCheck = new WorkFlowUserCheck(userId, check_id);
        Long _curCheckIndex = curCheckIndex;
        boolean addIndexFlag = addIndex != null && addIndex.length > 0 && addIndex[0];


        if(CollectionUtils.isEmpty(check_ids)){
            List<WorkFlowUserCheck> userChecks = new ArrayList<>();
            userChecks.add(userCheck);
            check_ids = new ArrayList<>();
            check_ids.add(userChecks);
            curNode.setCheck_ids(check_ids);
        }else{
            if (check_ids.size() == _curCheckIndex) {
                List<WorkFlowUserCheck> userChecks = new ArrayList<>();
                userChecks.add(userCheck);
                check_ids.add(userChecks);
            } else if (check_ids.size() > _curCheckIndex) {
                List<WorkFlowUserCheck> userChecks = check_ids.get(_curCheckIndex.intValue());
                userChecks.add(userCheck);
            } else {
                throw new CommonException("当前伦次审批不匹配");
            }
        }


        if (addIndexFlag) {
            _curCheckIndex = curCheckIndex + 1;
        }
        curNode.setCur_check_index(_curCheckIndex);

/*        if (CollectionUtils.isEmpty(check_ids)) {
            List<WorkFlowUserCheck> userChecks = new ArrayList<>();
            userChecks.add(userCheck);
            check_ids = new ArrayList<>();
            check_ids.add(userChecks);
            curNode.setCheck_ids(check_ids);
        } else {
            if (check_ids.size() == _curCheckIndex) {
                List<WorkFlowUserCheck> userChecks = new ArrayList<>();
                userChecks.add(userCheck);
                check_ids.add(userChecks);
            } else if (check_ids.size() > _curCheckIndex) {
                List<WorkFlowUserCheck> userChecks = check_ids.get(_curCheckIndex.intValue());
                userChecks.add(userCheck);
            } else if (check_ids.size() == _curCheckIndex - 1) {
                if (!addIndexFlag) {
                    List<WorkFlowUserCheck> userChecks = new ArrayList<>();
                    check_ids.add(userChecks);
                }
                List<WorkFlowUserCheck> userChecks2 = new ArrayList<>();
                userChecks2.add(userCheck);
                check_ids.add(userChecks2);
            } else {
                throw new CommonException("当前伦次审批不匹配");
            }
        }*/
    }

    /**
     * 查询流程上层表数据
     */
    private WFData getWFData(){
        List<WFData> wfDatas = workFlowUtil.wfDataService.list(new QueryWrapper<WFData>()
                .eq("work_flow_default_id", data.getFlow_default_id())
                .eq("data_id", data.getId()).orderByDesc("create_at"));
        if(CollectionUtils.isEmpty(wfDatas)) throw new CommonException("数据错误，数据不存在");
        //if(wfDatas.size() > 1) throw new CommonException("数据错误，数据存在多条");
        return wfDatas.get(0);
    }

    /**
     * 获取下一节点id
     *
     * @param sourceNodeId 起点节点id
     * @return 下一节点id，为null时，无需流转，只需要插入审批记录
     */
    private String getNextNodeId(String sourceNodeId){
        List<WorkFlowLine> temp = new ArrayList<>();
        for (WorkFlowLine workFlowLine : workFlow.getLineList()) {
            if (checkLine(workFlowLine, sourceNodeId)) {
                temp.add(workFlowLine);
            }
        }
        if (temp.size() > 1) {
            throw new CommonException("下一节点存在多个");
        } else if (temp.size() == 0) {
            throw new CommonException("不存在下一节点");
        } else if (!checkNextNodeSwitch(workFlow, temp.get(0).getTo())) {
            log.info("进入提交人节点关闭检查");
            return getNextNodeId(temp.get(0).getTo());
        } else {
            if (isBegin || toNextByNodeType()) {
                return temp.get(0).getTo();
            } else {
                return null;
            }
        }
    }

    /**
     * 根据会签、或签情况，判断是否能流转到下一个节点
     */
    private boolean toNextByNodeType(){
        log.info("进入会签或签检查");
        if (userIds.size() < 1) {
            throw new CommonException("出错，所有符合条件的审批人应>=1人");
        }
        WorkFlowNode node = getNodeByNodeId(workFlow, curNodeId);
        if (node == null) {
            throw new CommonException("当前节点不存在");
        }

        List<List<WorkFlowUserCheck>> check_ids = node.getCheck_ids();
        if (check_ids.size() < curCheckIndex + 1) {
            // 当前审批为第一轮审批
            // 审批类型是或签，或者，userIds只包含当前审批人一人
            return (node.getNodeType() == 2 || (userIds.size() == 1 && userIds.get(0).equals(userId)));
        } else {
            // 当前审批非第一轮审批
            List<WorkFlowUserCheck> userChecks = check_ids.get(curCheckIndex.intValue());
            if (node.getNodeType() == 2) {
                // 或签的情况
                if (userChecks == null || userChecks.size() == 0) {
                    // 当前轮审批中是第一个
                    return (userIds.contains(userId));
                } else {
                    // 当前轮审批中不是第一个
                    throw new CommonException("出错，或签情况下，不存在非第一次审批");
                }
            }
            if (node.getNodeType() == 1) {
                // 会签的情况
                if (userChecks == null || userChecks.size() == 0) {
                    // 当前轮审批中是第一个
                    return (userIds.size() == 1 && userIds.get(0).equals(userId));
                } else {
                    // 当前轮审批中不是第一个
                    List<Long> checkedIds = new ArrayList<>();
                    for (WorkFlowUserCheck userCheck : userChecks) {
                        checkedIds.add(userCheck.getCheckId());
                    }
                    List<WFCheck> wfChecks = workFlowUtil.wfCheckService.list(new QueryWrapper<WFCheck>().in("id", checkedIds));
                    if (wfChecks == null || wfChecks.size() == 0 || wfChecks.size() > userChecks.size()) {
                        throw new CommonException("出错，审批表数据与json中的check_ids不匹配");
                    }
                    boolean flag = true;
                    for (WFCheck wfCheck : wfChecks) {
                        flag = flag && (userIds.contains(wfCheck.getUser_id()) && wfCheck.getType() == 1);
                    }
                    if (!flag) {
                        throw new CommonException("出错，当前轮审批已存在非通过操作");
                    }
                    // 是否只剩下当前人未审批
                    return wfChecks.size() == userIds.size() - 1;
                }
            }
        }
        return false;
    }

    /**
     * 校验节点是否能通过该连接线
     *
     * @param line 连接线
     * @return true:成功  false:失败
     */
    private boolean checkLine(WorkFlowLine line, String sourceNodeId){
        if (line.getFrom().equals(sourceNodeId)) {
            List<WorkFlowPropertyData> conditions = line.getData();
            if (conditions == null || conditions.size() == 0) return true;
            StringBuffer conditionJSStr = new StringBuffer();
            for (WorkFlowPropertyData condition : conditions) {
                conditionJSStr.append(getJSStrByCondition(data, condition, false));
            }
            return generateConditionResult(conditionJSStr.toString());
        }
        return false;
    }

    /**
     * 校验节点是否能通过该连接线
     *
     * @param line 连接线
     * @return true:成功  false:失败
     */
    private static <T extends FlowBusinessDataSuperEntity> boolean staticCheckLine(WorkFlowLine line, String sourceNodeId, T data) throws Exception {
        if (line.getFrom().equals(sourceNodeId)) {
            List<WorkFlowPropertyData> conditions = line.getData();
            if (conditions == null || conditions.size() == 0) return true;
            StringBuffer conditionJSStr = new StringBuffer();
            for (WorkFlowPropertyData condition : conditions) {
                conditionJSStr.append(getJSStrByCondition(data, condition, false));
            }
            return generateConditionResult(conditionJSStr.toString());
        }
        return false;
    }

    /**
     * 检查数据的当前节点与审批节点是否一致
     *
     * @param checkNodeId 审批节点
     */
    private void checkNodeId(String checkNodeId){
        if (!checkNodeId.equals(data.getFlow_current_node_id())) {
            WFData wfData = getWFData();
            if(wfData == null) throw new CommonException("数据错误，流程data不存在");
            int checkCurNode = checkNotCurNode(workFlow, wfData.getPrev_node_id());
            if (checkCurNode == 0) {
                throw new CommonException("操作失败，该单据提交");
            } else if (checkCurNode == 2) {
                throw new CommonException("操作失败，该单据已被其他审批人退回");
            } else if (checkCurNode == 3) {
                throw new CommonException("操作失败，该单据已被其他审批人重审");
            } else {
                throw new CommonException("审批节点与数据当前节点不一致");
            }
        }
    }

    /**
     * 校验当前节点的操作人是否符合规则
     *
     * @return true:成功  false:失败
     */
    private boolean userCanOperate() {
        WorkFlowNode node = getNodeByNodeId(workFlow, curNodeId);
        return node != null && checkNode(node);
    }

    /**
     * 校验节点规则
     *
     * @param node 节点
     * @return true:成功  false:失败
     */
    private boolean checkNode(WorkFlowNode node){
        // 节点可选
        if (node.getNodeCanChooseSwitch() == 1) {
            // 将所有可选人存入节点的全部审批人
            for (String user : node.getNodeCanChooseValueSubmit()) {
                this.userIds.add(Long.parseLong(user));
            }
            // 检查当前用户是否在配置的可选人员中
            return checkNodeCanChoose(node, userId);
        } else {
            List<User> users = workFlowUtil.userService.getActiveUsers(null);
            if(CollectionUtils.isNotEmpty(users)) companyUsers = users.stream().map(User::getId).collect(Collectors.toList());
            // 校验data配置项
            return checkNodeData(node);
        }
    }

    /**
     * 校验data配置项
     */
    private boolean checkNodeData(WorkFlowNode node){
        List<WorkFlowPropertyData> conditions = node.getData();
        if (conditions == null) return false;
        for (long user : companyUsers) {
            StringBuffer conditionJSStr = new StringBuffer();
            for (WorkFlowPropertyData condition : conditions) {
                conditionJSStr.append(getJSStrByCondition(data, condition, true, user));
            }
            if (generateConditionResult(conditionJSStr.toString())) userIds.add(user);
        }
        return userIds.contains(userId);
    }

    /**
     * 静态校验data配置项，用于显示当前流程
     */
    private static boolean staticCheckNodeData(WorkFlowNode node, FlowBusinessDataSuperEntity data) throws Exception {
        List<WorkFlowPropertyData> conditions = node.getData();
        if (conditions == null) return false;
        StringBuffer conditionJSStr = new StringBuffer();
        for (WorkFlowPropertyData condition : conditions) {
            conditionJSStr.append(getJSStrByCondition(data, condition, true));
        }
        return generateConditionResult(conditionJSStr.toString());
    }

    /**
     * 用javascript引擎动态编译
     */
    private static boolean generateConditionResult(String jsStr){
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("javascript");
        try {
            return (Boolean) engine.eval(jsStr);
        }catch (ScriptException e){
            log.error("js条件运行异常",e);
            throw new CommonException("流程异常");
        }

    }

    /**
     * 生成每个配置条件的jsstr
     *
     * @param condition 条件对象
     * @param isNode    是否是node配置项
     * @param ids       0:userId
     */
    private static <T extends FlowBusinessDataSuperEntity> String getJSStrByCondition(T data, WorkFlowPropertyData condition, Boolean isNode, Long... ids) {
        StringBuffer str = new StringBuffer();

        if ("left".equals(condition.getType())) str.append("(");
        if ("right".equals(condition.getType())) str.append(")");
        if ("and".equals(condition.getType())) str.append("&&");
        if ("or".equals(condition.getType())) str.append("||");

        if ("condition".equals(condition.getType())) {
            WorkFlowPropertyDataConditionValue value = JSON.parseObject(JSON.toJSONString(condition.getValue()), WorkFlowPropertyDataConditionValue.class);
            List<String> innerType = value.getType();
            if (isNode) {
                if (ids == null) throw new CommonException("节点规则校验出错，未传ids");
                if (ids[0] == null) throw new CommonException("节点规则校验出错，未传当前人id");
                switch (Integer.parseInt(innerType.get(1))) {
                    // 人员
                    case 1:
                        str.append(checkNodeConditionValue_person(value, ids[0]));
                        break;
                    // 部门领导
                    case 2:
                        List<Long> depIds = new ArrayList<>();
                        depIds.add(data.getFlow_applyer_org_id());
                        str.append(checkNodeConditionValue_departmentManager(value, ids[0], depIds));
                        break;
                    // 公司领导
                    case 3:
                        str.append(checkNodeConditionValue_companyManager(value, ids[0], data.getFlow_applyer_org_id()));
                        break;
                    // 部门职位
                    case 4:
                        str.append(checkNodeConditionValue_departmentJob(value, ids[0]));
                        break;
                    // 提交人自身
                    case 5:
                        str.append(checkNodeConditionValue_self(data.getFlow_applyer_id(), ids[0]));
                        break;
                }
            } else {
                Integer typeOne = Integer.parseInt(innerType.get(0));
                String typeTwo = innerType.get(1);
                if (typeOne == 1) {
                    // 默认配置项：提交人、提交人组织
                    if ("applyer".equals(typeTwo))
                        str.append(checkLineConditionValue_applyer(value, data.getFlow_applyer_id()));
                    if ("applyer_org".equals(typeTwo))
                        str.append(checkLineConditionValue_applyerOrg(value, data.getFlow_applyer_org_id()));
                } else if (typeOne == 2) {
                    //表单相关配置项
                    String operator = value.getOperator();
                    Object obj = getGetMethod(data, typeTwo);
                    if (obj == null) str.append(false);
                    else {
                        String innerValue = value.getValue();
                        // 正则校验是否为日期
                        boolean isDate = Pattern.matches("^20[0-9]{2}-((0[1-9])|(1[0-2]))-(([0-2][0-9])|(3[0-1]))(\\s+(([0-1][0-9])|(2[0-3])):[0-5][0-9]:[0-5][0-9])?$", innerValue);
                        if (isDate) {
                            if (obj instanceof Date) {
                                try {
                                    str.append(checkLineConditionValue_form_date(operator, sdf.parse(sdf.format(obj)), sdf.parse(innerValue)));
                                }catch (ParseException e){
                                    log.error("流程日期转换错误", e);
                                    throw new CommonException("流程异常");
                                }
                            } else throw new CommonException("连接线，表单相关，日期类型值" + typeTwo + "，表字段不匹配");
                        } else {
                            if (obj instanceof Number)
                                str.append(checkLineConditionValue_form_number(operator, obj, innerValue));
                            else if (obj instanceof String)
                                str.append(checkLineConditionValue_form_string(operator, obj, innerValue));
                            else throw new CommonException("连接线，表单相关，" + typeTwo + "非数值或字符串");
                        }
                    }
                }
            }
        }
        return str.toString();
    }

    /**
     * 连接线配置项，表单相关，日期类型
     */
    private static boolean checkLineConditionValue_form_date(String operator, Date obj1, Date obj2) {
        long date1 = obj1.getTime();
        long date2 = obj2.getTime();
        if ("=".equals(operator)) return date1 == date2;
        if (">".equals(operator)) return date1 > date2;
        if ("<".equals(operator)) return date1 < date2;
        if (">=".equals(operator)) return date1 >= date2;
        if ("<=".equals(operator)) return date1 <= date2;
        return false;
    }

    /**
     * 连接线配置项，表单相关，字符串类型
     */
    private static boolean checkLineConditionValue_form_string(String operator, Object obj1, String obj2) {
        String str1 = String.valueOf(obj1);
        String str2 = String.valueOf(obj2);
        if ("=".equals(operator)) return str1.equals(str2);
        if ("<>".equals(operator)) return !str1.equals(str2);
        if ("like".equals(operator)) return str1.contains(str2);
        if ("unlike".equals(operator)) return !str1.contains(str2);
        return false;
    }

    /**
     * 连接线配置项，表单相关，数字类型
     */
    private static boolean checkLineConditionValue_form_number(String operator, Object obj1, String obj2) {
        BigDecimal num1BD = new BigDecimal(String.valueOf(obj1));
        BigDecimal num2BD = new BigDecimal(obj2);
        if ("=".equals(operator)) return num1BD.compareTo(num2BD) == 0;
        if (">".equals(operator)) return num1BD.compareTo(num2BD) > 0;
        if ("<".equals(operator)) return num1BD.compareTo(num2BD) < 0;
        if (">=".equals(operator)) return num1BD.compareTo(num2BD) >= 0;
        if ("<=".equals(operator)) return num1BD.compareTo(num2BD) <= 0;
        return false;
    }

    /**
     * 连接线配置项，提交人组织
     */
    private static boolean checkLineConditionValue_applyerOrg(WorkFlowPropertyDataConditionValue value, Long applyer_org) {
        if ("=".equals(value.getOperator())) return applyer_org == Long.parseLong(value.getValue());
        if ("<>".equals(value.getOperator())) return applyer_org != Long.parseLong(value.getValue());
        List<Long> departmentIds = workFlowUtil.departmentService.getChildrenIdsById(Long.parseLong(value.getValue()));
        if ("belong".equals(value.getOperator())) return departmentIds.contains(applyer_org);
        if ("unbelong".equals(value.getOperator())) return !departmentIds.contains(applyer_org);
        return false;
    }

    /**
     * 连接线配置项，提交人
     */
    private static boolean checkLineConditionValue_applyer(WorkFlowPropertyDataConditionValue value, Long applyer) {
        if ("=".equals(value.getOperator())) return applyer == Long.parseLong(value.getValue());
        if ("<>".equals(value.getOperator())) return applyer != Long.parseLong(value.getValue());
        return false;
    }

    /**
     * 节点配置项，人员选择
     */
    private static boolean checkNodeConditionValue_person(WorkFlowPropertyDataConditionValue value, Long userId) {
        if ("=".equals(value.getOperator())) return userId == Long.parseLong(value.getValue());
        if ("<>".equals(value.getOperator())) return userId != Long.parseLong(value.getValue());
        return false;
    }

    /**
     * 节点配置项，部门领导
     */
    private static boolean checkNodeConditionValue_departmentManager(WorkFlowPropertyDataConditionValue value, Long userId, List<Long> depIds) {
        List<String> jobs = new ArrayList<>();
        jobs.add(value.getValue());
        List<Long> userIds = workFlowUtil.userService.getUserIdsByDepartmentIdsAndJobs(depIds,jobs);
        if ("=".equals(value.getOperator())) return userIds.contains(userId);
        if ("<>".equals(value.getOperator())) return !userIds.contains(userId);
        return false;
    }

    /**
     * 节点配置项，公司领导
     */
    private static boolean checkNodeConditionValue_companyManager(WorkFlowPropertyDataConditionValue value, Long userId, Long departmentId) {
        List<String> jobs = new ArrayList<>();
        jobs.add(value.getValue());
        List<Long> userIds = workFlowUtil.userService.getSupperUserIdsByDepartmentIdAndJobs(departmentId, jobs);
        if ("=".equals(value.getOperator())) return userIds.contains(userId);
        if ("<>".equals(value.getOperator())) return !userIds.contains(userId);
        return false;
    }

    /**
     * 节点配置项，部门职位
     */
    private static boolean checkNodeConditionValue_departmentJob(WorkFlowPropertyDataConditionValue value, Long userId) {
        List<String> departmentId_job = new ArrayList<>();
        departmentId_job.add(value.getValue());
        List<Long> userIds = workFlowUtil.userService.getUserIdsByDepartmentIdJob(departmentId_job);
        if ("=".equals(value.getOperator())) return userIds.contains(userId);
        if ("<>".equals(value.getOperator())) return !userIds.contains(userId);
        return false;
    }

    /**
     * 节点配置项，提交人自身
     */
    private static boolean checkNodeConditionValue_self(Long applyer, Long userId) {
        return applyer.equals(userId);
    }

    /**
     * 检查用户id是否在配置的可选人员中
     *
     * @param userId 用户id
     */
    private static boolean checkNodeCanChoose(WorkFlowNode node, Long userId) {
        return node.getNodeCanChooseValueSubmit().contains(String.valueOf(userId));
    }

    /**
     * 检查下一节点是否关闭
     *
     * @param nextNodeId 下一节点id
     * @return true:下一节点开启状态；false：下一节点已关闭
     */
    private static boolean checkNextNodeSwitch(WorkFlow workFlow, String nextNodeId) {
        WorkFlowNode nextNode = getNodeByNodeId(workFlow, nextNodeId);
        return (nextNode != null && ((nextNode.getNodeSwitch() == 0) || (nextNode.getNodeSwitch() == 1 && nextNode.getNodeSwitchSubmit() == 1)));
    }

    /**
     * 当审批节点与流程当前节点不一致时，检查审批节点是否出现退回或重审操作
     *
     * @param nodeId 审批节点id
     * @return -1：之前无退回或重审；2：退回；3：重审。此处与wf_check表的type字段对应，请查看数据表的注释
     */
    private static int checkNotCurNode(WorkFlow workFlow, String nodeId) {
        if(StringUtils.isEmpty(nodeId)) return -1;
        String [] _nodeIds = nodeId.split(",");
        String _nodeId = _nodeIds[_nodeIds.length-1];
        WorkFlowNode node = getNodeByNodeId(workFlow, _nodeId);
        if (node == null) return -1;

        List<List<WorkFlowUserCheck>> check_ids = node.getCheck_ids();
        if (check_ids == null) return -1;

        List<WorkFlowUserCheck> userChecks = node.getCheck_ids().get(node.getCur_check_index().intValue()-1);
        if (userChecks == null) return -1;

        WorkFlowUserCheck lastUserCheck = userChecks.get(userChecks.size() - 1);
        WFCheck check = workFlowUtil.wfCheckService.getById(lastUserCheck.getCheckId());
        return check != null ? check.getType() : -1;
    }

    /**
     * 查找结束节点
     */
    private static WorkFlowNode getEndNode(WorkFlow workFlow) {
        List<WorkFlowNode> nodeList = workFlow.getNodeList();
        for (WorkFlowNode node : nodeList) {
            if (node.getType().equals("end")) return node;
        }
        return null;
    }

    /**
     * 根据属性，获取get方法
     *
     * @param ob   对象
     * @param name 属性名
     */
    private static Object getGetMethod(Object ob, String name){
        Method[] m = ob.getClass().getMethods();
        for (int i = 0; i < m.length; i++) {
            if (("get" + name).toLowerCase().equals(m[i].getName().toLowerCase())) {
                try{
                    return m[i].invoke(ob);
                }catch (Exception e){
                    log.error("反射方法失败", e);
                    throw new CommonException("流程异常");
                }

            }
        }
        return null;
    }

    private int updateData(T data){
        if (this.baseMapper != null) {
            return baseMapper.updateById(data);
        } else {
            return (Integer) updateDataByClass(data);
        }
    }

    /**
     * 根据class反射mapper的selectById方法，查询数据
     * @param id 数据id
     */
    private Object getDataByClass(Long id) {
        String dataPath = SqlHelper.table(this.entityClass).getCurrentNamespace();
        Class<?> mapperClass = null;
        try {
            mapperClass = Class.forName(dataPath);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            Object mapperServiceBean = SpringContextUtil.getBean(mapperClass);
            this.baseMapper = (M) mapperServiceBean;
            Method mapperServiceBeanMethod = ReflectionUtils.findMethod(mapperServiceBean.getClass(), "selectById", Serializable.class);
            // 执行方法
            return ReflectionUtils.invokeMethod(mapperServiceBeanMethod, mapperServiceBean, id);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private Object updateDataByClass(T data){
        String dataPath = SqlHelper.table(this.entityClass).getCurrentNamespace();
        Class<?> mapperClass = null;
        try {
            mapperClass = Class.forName(dataPath);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        try {
            Object mapperServiceBean = SpringContextUtil.getBean(mapperClass);
            Method mapperServiceBeanMethod = ReflectionUtils.findMethod(mapperServiceBean.getClass(), "updateById", this.entityClass);
            // 执行方法
            return ReflectionUtils.invokeMethod(mapperServiceBeanMethod, mapperServiceBean, data);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 下划线转换为驼峰
     *
     * @param line             下划线字符串
     * @param firstIsUpperCase 首字母是否转换为大写
     */
    private static String underline2Camel(String line, boolean... firstIsUpperCase) {
        String str = "";

        if (StringUtils.isBlank(line)) {
            return str;
        } else {
            StringBuilder sb = new StringBuilder();
            String[] strArr;
            // 不包含下划线，且第二个参数是空的
            if (!line.contains("_") && firstIsUpperCase.length == 0) {
                sb.append(line.substring(0, 1).toLowerCase()).append(line.substring(1));
                str = sb.toString();
            } else if (!line.contains("_") && firstIsUpperCase.length != 0) {
                if (!firstIsUpperCase[0]) {
                    sb.append(line.substring(0, 1).toLowerCase()).append(line.substring(1));
                    str = sb.toString();
                } else {
                    sb.append(line.substring(0, 1).toUpperCase()).append(line.substring(1));
                    str = sb.toString();
                }
            } else if (line.contains("_") && firstIsUpperCase.length == 0) {
                strArr = line.split("_");
                for (String s : strArr) {
                    sb.append(s.substring(0, 1).toUpperCase()).append(s.substring(1));
                }
                str = sb.toString();
                str = str.substring(0, 1).toLowerCase() + str.substring(1);
            } else if (line.contains("_") && firstIsUpperCase.length != 0) {
                strArr = line.split("_");
                for (String s : strArr) {
                    sb.append(s.substring(0, 1).toUpperCase()).append(s.substring(1));
                }
                if (!firstIsUpperCase[0]) {
                    str = sb.toString();
                    str = str.substring(0, 1).toLowerCase() + str.substring(1);
                } else {
                    str = sb.toString();
                }
            }
        }
        return str;
    }
}



